// generics/coffee/CoffeeSupplier.java
// (c)2021 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
// {java generics.coffee.CoffeeSupplier}
package onjava.generics.coffee;

import java.util.*;
import java.util.function.*;
import java.util.stream.*;
import java.lang.reflect.InvocationTargetException;

/**
 * 泛型接口 -> 生成器： 是一种用于创建对象的类，实际上是工厂方法（Factory Method）设计模式的一种特殊形式
 *
 * @author Lucky Yang
 */
public class CoffeeSupplier
    implements Supplier<Coffee>, Iterable<Coffee> {
  private Class<?>[] types = { Latte.class, Mocha.class,
      Cappuccino.class, Americano.class, Breve.class, };
  private static Random rand = new Random(47);

  public CoffeeSupplier() {
  }

  /** For iteration */
  private int size = 0;

  public CoffeeSupplier(int sz) {
    size = sz;
  }

  @Override
  public Coffee get() {
    try {
      return (Coffee) types[rand.nextInt(types.length)]
          .getConstructor().newInstance();
      // Report programmer errors at runtime:
    } catch (InstantiationException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
      throw new RuntimeException(e);
    }
  }

  class CoffeeIterator implements Iterator<Coffee> {
    int count = size;

    @Override
    public boolean hasNext() {
      return count > 0;
    }

    @Override
    public Coffee next() {
      count--;
      return CoffeeSupplier.this.get();
    }

    /**
     * Not implemented
     */
    @Override
    public void remove() {
      throw new UnsupportedOperationException();
    }
  }

  @Override
  public Iterator<Coffee> iterator() {
    return new CoffeeIterator();
  }

  public static void main(String[] args) {
    int size = 5;

    // 实现了Supplier接口
    Stream.generate(new CoffeeSupplier())
        .limit(size)
        .forEach(System.out::println);

    // 实现了Iterable接口
    for (Coffee c : new CoffeeSupplier(size)) {
      System.out.println(c);
    }
  }
}
/*
 * Output:
 * Americano 0
 * Latte 1
 * Americano 2
 * Mocha 3
 * Mocha 4
 * Breve 5
 * Americano 6
 * Latte 7
 * Cappuccino 8
 * Cappuccino 9
 */
